/* Author: David McCoy dave.mccoy@cospandesign.com
 *
 *     This file is part of DLCM\SubServ.
 *
 *  DLCM\SubServ is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  DLCM\SubServ is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with DLCM\SubServ.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

/*
 * SliderWidget.java
 *
 * Used to send numerical data across LCM/DLCM
 *
 * Created on Mar 31, 2010, 4:39:46 PM
 */

package com.cospandesign.gui.pubsub.widgets;

import pubsub.PubSubManager;
import dlcm.Member;
import dlcm.Structure;
import java.util.Date;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


public class SliderWidget extends javax.swing.JFrame implements Widget{

    String ChannelName;
    String MemberName;
    dlcm.Structure mStructure;
    dlcm.Member mMember;
    PubSubManager Parent;

    Class DataClass;

    int MaxSignedRange = 127;
    int MaxUnsignedRange = 128;
    int MaxUnsignedFullRange = 255;

    int MinSignedRange = 0;

    long TimeOut = 0;

    private static int READ_DELAY = 20;

    public SliderWidget() {
        initComponents();
    }
    
    // <editor-fold defaultstate="collapsed" desc="Static Functions">
    public static String GetWidgetName() {
        return "Slider Widget";
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Inherited Widget Functions">
    public void ReceiveMessage(Structure structure) {
        int value = 0;
        if (DataClass.equals(Byte.class)){
            value = (Byte)structure.getMember(MemberName).Data;
        }
        else if (DataClass.equals(Short.class)){
            value = (Short)structure.getMember(MemberName).Data;
        }

        if (this.SignedCheckBox.isSelected()){
            IntegerSlider.setValue(value);
            return;
        }
        //unsigned
        if (this.FullRangeCheckBox.isSelected()){
            value += MaxUnsignedRange;
            
        }
        //EnableReading = false;
        //Timer DelayTimer = new Timer();
        //DelayTimer.schedule(Delay, READ_DELAY);
        IntegerSlider.setValue(new Integer (value));
    }

    public boolean CanUseMember(Member member) {
        if (member.Data.getClass().equals(Byte.class)){
            return true;
        }
        if (member.Data.getClass().equals(Short.class)){
            return true;
        }
        return false;


    }

    public void SetupWidget(String channelName, String memberName, Structure structure, PubSubManager parent) {
        ChannelName = channelName;
        MemberName = memberName;
        mStructure = structure;
        mMember = mStructure.getMember(memberName);
        Parent = parent;

        DataClass = mMember.Data.getClass();

        setTitle(memberName + "Slider Widget");
        setVisible(true);

        if (mMember.Data.getClass().equals(Byte.class)){
            MinSignedRange = Byte.MIN_VALUE;
            MaxSignedRange = Byte.MAX_VALUE;
        }
        if (mMember.Data.getClass().equals(Short.class)){
            MinSignedRange = Short.MIN_VALUE;
            MaxSignedRange = Short.MAX_VALUE;
        }
        if (mMember.Data.getClass().equals(Integer.class)){
            MinSignedRange = Integer.MIN_VALUE;
            MaxSignedRange = Integer.MAX_VALUE;
        }

        MaxUnsignedRange = MaxSignedRange;
        if (((long)(MaxSignedRange * 2) - 1) > (Integer.MAX_VALUE)){
            MaxSignedRange = Integer.MAX_VALUE;
        }
        else{
            MaxUnsignedFullRange = ((MaxSignedRange * 2) - 1);
        }


        setRange();

        IntegerSlider.addChangeListener(new ChangeListener(){

            public void stateChanged(ChangeEvent e) {
                IntegerSliderChangeListener();
            }
            
        });


    }

    private void setRange(){
        boolean signed = SignedCheckBox.isSelected();
        boolean fullRange = FullRangeCheckBox.isSelected();
        boolean auto = !ManualSelectRangeCheckBox.isSelected();
        if (auto){
            if (signed){
                IntegerSlider.setMaximum(this.MaxSignedRange);
                IntegerSlider.setMinimum(this.MinSignedRange);
            }
            else {
                //not signed
                IntegerSlider.setMinimum(0);
                if (fullRange){
                    IntegerSlider.setMaximum(this.MaxUnsignedFullRange);
                }
                else {
                    IntegerSlider.setMaximum(MaxSignedRange);
                }
            }
        }
        //Manual Range Select
        else {

            int maxValue = this.MaxSignedRange;
            int minValue = this.MinSignedRange;

            String minText = MinValueFTextField.getText();
            String maxText = MaxValueFTextField.getText();

            int highNum = 0;
            int lowNum = 0;
            try {
                highNum = Integer.parseInt(maxText);
                lowNum = Integer.parseInt(minText);
            }
            catch (NumberFormatException e){
                SetRangeToDefault();
                return;
            }

            if (!SignedCheckBox.isSelected()){
                minValue = 0;
                if (this.FullRangeCheckBox.isSelected()){
                    maxValue = this.MaxUnsignedFullRange;
                }
                else {
                    maxValue = this.MaxUnsignedRange;
                }

            }

            if (lowNum < minValue){
                lowNum = minValue;
            }
            if (highNum > maxValue){
                highNum = maxValue;
            }

            if (highNum <= lowNum){
                SetRangeToDefault();
            }

            IntegerSlider.setMinimum(lowNum);
            IntegerSlider.setMaximum(highNum);

            
        }
        //Now set the increments
        int majorSpacing = (IntegerSlider.getMaximum() - IntegerSlider.getMinimum()) / 10;
        if (majorSpacing == 0){
            majorSpacing = 1;
        }
        if (IntegerSlider.getMaximum() <= 256){
            IntegerSlider.setMajorTickSpacing(majorSpacing);
        }
    }

    private void SetRangeToDefault(){
        this.ManualSelectRangeCheckBox.setSelected(true);
        this.SignedCheckBox.setSelected(true);
        IntegerSlider.setMaximum(this.MaxSignedRange);
        IntegerSlider.setMinimum(this.MinSignedRange);
        int majorSpacing = (IntegerSlider.getMaximum() - IntegerSlider.getMinimum()) / 10;
        if (majorSpacing == 0){
            majorSpacing = 1;
        }
        IntegerSlider.setMajorTickSpacing(majorSpacing);

    }


    public void setWidgetVisibility(boolean visible) {
        setVisible(visible);
    }
    // </editor-fold>

    private void PublishValue (Integer value){
        if (DataClass.equals(Byte.class)){
            mMember.Data = value.byteValue();
        }
        else if (DataClass.equals(Short.class)){
            mMember.Data = value.shortValue();
        }
        else {
            mMember.Data = value;
        }

        this.Parent.PublishStructure(ChannelName, mStructure);
    }

    private void IntegerSliderChangeListener(){
        Date now = new Date();
        long nowMillis = now.getTime();
        if (nowMillis < TimeOut){
            return;
        }
        TimeOut = nowMillis + READ_DELAY;

        Integer value = IntegerSlider.getValue();

        if (this.FullRangeCheckBox.isSelected()){
            value -= this.MinSignedRange;
        }

        PublishValue(value);

    }


    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

        integerToText = new com.cospandesign.gui.pubsub.widgets.IntegerToText();
        IntegerSlider = new javax.swing.JSlider();
        ValueTextField = new javax.swing.JTextField();
        jPanel1 = new javax.swing.JPanel();
        ManualSelectRangeCheckBox = new javax.swing.JCheckBox();
        jLabel2 = new javax.swing.JLabel();
        MaxValueFTextField = new javax.swing.JFormattedTextField();
        jLabel3 = new javax.swing.JLabel();
        MinValueFTextField = new javax.swing.JFormattedTextField();
        SetMinMaxButton = new javax.swing.JButton();
        SignedCheckBox = new javax.swing.JCheckBox();
        jLabel4 = new javax.swing.JLabel();
        FullRangeCheckBox = new javax.swing.JCheckBox();

        setIconImage(java.awt.Toolkit.getDefaultToolkit().getImage(getClass().getResource("/com/cospandesign/resources/cospandesign.png")));

        IntegerSlider.setMajorTickSpacing(10);
        IntegerSlider.setOrientation(javax.swing.JSlider.VERTICAL);
        IntegerSlider.setPaintLabels(true);
        IntegerSlider.setPaintTicks(true);
        IntegerSlider.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        IntegerSlider.setName("IntegerSlider"); // NOI18N

        ValueTextField.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
        ValueTextField.setName("ValueTextField"); // NOI18N

        org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ, IntegerSlider, org.jdesktop.beansbinding.ELProperty.create("${value}"), ValueTextField, org.jdesktop.beansbinding.BeanProperty.create("text_ON_ACTION_OR_FOCUS_LOST"), "IntegerValue");
        binding.setConverter(integerToText);
        bindingGroup.addBinding(binding);

        ValueTextField.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                ValueTextFieldKeyPressed(evt);
            }
        });

        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Select Range"));
        jPanel1.setName("jPanel1"); // NOI18N

        ManualSelectRangeCheckBox.setText("Manual");
        ManualSelectRangeCheckBox.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
        ManualSelectRangeCheckBox.setName("ManualSelectRangeCheckBox"); // NOI18N
        ManualSelectRangeCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                ManualSelectRangeCheckBoxActionPerformed(evt);
            }
        });

        jLabel2.setText("Max");
        jLabel2.setName("jLabel2"); // NOI18N

        MaxValueFTextField.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter(new java.text.DecimalFormat("#0"))));
        MaxValueFTextField.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
        MaxValueFTextField.setText("100");
        MaxValueFTextField.setName("MaxValueFTextField"); // NOI18N

        jLabel3.setText("Min");
        jLabel3.setName("jLabel3"); // NOI18N

        MinValueFTextField.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter(new java.text.DecimalFormat("#0"))));
        MinValueFTextField.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
        MinValueFTextField.setName("MinValueFTextField"); // NOI18N

        SetMinMaxButton.setText("Set Min/Max");
        SetMinMaxButton.setEnabled(false);
        SetMinMaxButton.setName("SetMinMaxButton"); // NOI18N

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel2)
                            .addComponent(jLabel3))
                        .addGap(88, 88, 88))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(MaxValueFTextField, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 102, Short.MAX_VALUE)
                            .addComponent(ManualSelectRangeCheckBox)
                            .addComponent(MinValueFTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 102, Short.MAX_VALUE))
                        .addContainerGap())))
            .addComponent(SetMinMaxButton, javax.swing.GroupLayout.DEFAULT_SIZE, 122, Short.MAX_VALUE)
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGap(25, 25, 25)
                        .addComponent(jLabel2))
                    .addComponent(ManualSelectRangeCheckBox))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(MaxValueFTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jLabel3)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(MinValueFTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 28, Short.MAX_VALUE)
                .addComponent(SetMinMaxButton))
        );

        SignedCheckBox.setText("Signed");
        SignedCheckBox.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
        SignedCheckBox.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
        SignedCheckBox.setName("SignedCheckBox"); // NOI18N
        SignedCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                SignedCheckBoxActionPerformed(evt);
            }
        });

        jLabel4.setText("Value");
        jLabel4.setName("jLabel4"); // NOI18N

        FullRangeCheckBox.setText("Full Range");
        FullRangeCheckBox.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
        FullRangeCheckBox.setName("FullRangeCheckBox"); // NOI18N
        FullRangeCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                FullRangeCheckBoxActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(IntegerSlider, javax.swing.GroupLayout.PREFERRED_SIZE, 47, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jLabel4)
                    .addComponent(ValueTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 134, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(SignedCheckBox)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(FullRangeCheckBox)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(IntegerSlider, javax.swing.GroupLayout.PREFERRED_SIZE, 257, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                        .addComponent(jLabel4)
                        .addGap(2, 2, 2)
                        .addComponent(ValueTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(SignedCheckBox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(FullRangeCheckBox))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                .addContainerGap())
        );

        bindingGroup.bind();

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void ManualSelectRangeCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ManualSelectRangeCheckBoxActionPerformed
        setRange();
    }//GEN-LAST:event_ManualSelectRangeCheckBoxActionPerformed

    private void SignedCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SignedCheckBoxActionPerformed
        setRange();
    }//GEN-LAST:event_SignedCheckBoxActionPerformed

    private void FullRangeCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_FullRangeCheckBoxActionPerformed
        setRange();
    }//GEN-LAST:event_FullRangeCheckBoxActionPerformed

    private void ValueTextFieldKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_ValueTextFieldKeyPressed
        if (evt.getKeyCode() == evt.VK_ENTER){

            Integer x = null;
            x = Integer.parseInt(this.ValueTextField.getText());
            this.IntegerSlider.setValue(x);
        }
    }//GEN-LAST:event_ValueTextFieldKeyPressed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JCheckBox FullRangeCheckBox;
    private javax.swing.JSlider IntegerSlider;
    private javax.swing.JCheckBox ManualSelectRangeCheckBox;
    private javax.swing.JFormattedTextField MaxValueFTextField;
    private javax.swing.JFormattedTextField MinValueFTextField;
    private javax.swing.JButton SetMinMaxButton;
    private javax.swing.JCheckBox SignedCheckBox;
    private javax.swing.JTextField ValueTextField;
    private com.cospandesign.gui.pubsub.widgets.IntegerToText integerToText;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JPanel jPanel1;
    private org.jdesktop.beansbinding.BindingGroup bindingGroup;
    // End of variables declaration//GEN-END:variables



}
